﻿#region License

// IOrganize.Files: a file system ETL processor
// Copyright © 2011 Business in Unison, Inc.
// 
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

#endregion

using System.Configuration;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Serialization;

namespace Patterns.Config
{
	/// <summary>
	/// 	Defines a config section that holds raw Xml data,
	/// 	rather than depend on a defined configuration model.
	/// 	Useful when the cost of creating a fully decorated
	/// 	configuration section object is too expensive for the task
	/// 	at hand.
	/// </summary>
	/// <example>
	/// 	<code><![CDATA[
	/// var settings = CurrentConfig.GetSection<ConfigSection>("mySection").Data.AsObject<MySettings>(...);
	/// ]]></code>
	/// </example>
	public class ConfigSection : ConfigurationSection
	{
		private readonly object _syncLock = new object();
		private XElement _data;

		/// <summary>
		/// 	Gets the data.
		/// </summary>
		[XmlIgnore]
		public XElement Data
		{
			get
			{
				if (_data == null)
				{
					lock (_syncLock)
					{
						if (_data == null)
							_data = new XElement(SectionInformation.Name);
					}
				}

				return _data;
			}
		}

		/// <summary>
		/// 	Gets a value indicating whether an unknown attribute is encountered during deserialization.
		/// </summary>
		/// <param name = "name">The name of the unrecognized attribute.</param>
		/// <param name = "value">The value of the unrecognized attribute.</param>
		/// <returns>
		/// 	<c>true</c> when an unknown attribute is encountered while deserializing; otherwise, <c>false</c>.
		/// </returns>
		protected override bool OnDeserializeUnrecognizedAttribute(string name, string value)
		{
			Data.Add(new XAttribute(name, value));
			return true;
		}

		/// <summary>
		/// 	Gets a value indicating whether an unknown element is encountered during deserialization.
		/// </summary>
		/// <param name = "elementName">The name of the unknown sub element.</param>
		/// <param name = "reader">The <see cref = "T:System.Xml.XmlReader" /> being used for deserialization.</param>
		/// <returns>
		/// 	<c>true</c> when an unknown element is encountered while deserializing; otherwise, <c>false</c>.
		/// </returns>
		/// <exception cref = "T:System.Configuration.ConfigurationErrorsException">
		/// 	The element identified by <paramref name = "elementName" /> is locked.
		/// 	- or -
		/// 	One or more of the element's attributes is locked.
		/// 	- or -
		/// 	<paramref name = "elementName" /> is unrecognized, or the element has an unrecognized attribute.
		/// 	- or -
		/// 	The element has a Boolean attribute with an invalid value.
		/// 	- or -
		/// 	An attempt was made to deserialize a property more than once.
		/// 	- or -
		/// 	An attempt was made to deserialize a property that is not a valid member of the element.
		/// 	- or -
		/// 	The element cannot contain a CDATA or text element.
		/// </exception>
		protected override bool OnDeserializeUnrecognizedElement(string elementName, XmlReader reader)
		{
			Data.Add(XElement.Load(reader.ReadSubtree()));
			return true;
		}
	}
}